import MySQLdb
import logging
import time
import unittest

# Singleton class to access the output database.
class PersistData():
	_iInstance = None
	
	def __init__(self, dbhost = "localhost", dbuser = "dbuser", dbpass = "dbpass", dbname = "dbname", retries="3"):
		if PersistData._iInstance is None:
			PersistData._iInstance = PersistData.Singleton(dbhost, dbuser, dbpass, dbname, retries)
		self.__dict__['_EventHandler_instance'] = PersistData._iInstance

	def __getattr__(self, aAttr):
		return getattr(self._iInstance, aAttr)

	def __setattr__(self, aAttr, aValue):
		return setattr(self._iInstance, aAttr, aValue)

	class Singleton:
		def __init__(self, dbhost, dbuser, dbpass, dbname, retries):
			self.db = MySQLdb.connect(host=dbhost, user=dbuser, passwd=dbpass, db=dbname)
			self.c = self.db.cursor()
			self.dbhost = dbhost
			self.dbuser = dbuser
			self.dbpass = dbpass
			self.dbname = dbname
			self.dbretries = retries

		def ringing(self, channel1, channel2):
			sql = """INSERT INTO channels (channel1, channel2, status, laststate) VALUES (%s, %s, 1, NULL)"""
			try:
				self.c.execute(sql, (channel1, channel2))
			except MySQLdb.OperationalError, reason:
				logging.critical("MySQLdb: %s" % reason)
				if not self._reconnect():
					return 0
				else:
					self.c.execute(sql, (channel1, channel2))
			return 1

		def oncall(self, channel1, channel2):
			sql = """UPDATE channels SET status=2 WHERE (channel1=%s AND channel2=%s) OR (channel1=%s AND channel2=%s)"""
			try:
				self.c.execute(sql, (channel1, channel2, channel2, channel1))
			except MySQLdb.OperationalError, reason:
				logging.critical("MySQLdb: %s" % reason)
				if not self._reconnect():
					return 0
				else:
					self.c.execute(sql, (channel1, channel2, channel2, channel1))
			return 1
				

		def hangup(self, channel):
			sql = """DELETE FROM channels WHERE channel1=%s OR channel2=%s"""
			try:
				self.c.execute(sql, (channel, channel))
			except MySQLdb.OperationalError, reason:
				logging.critical("MySQLdb: %s" % reason)
				if not self._reconnect():
					return 0
				else:
					self.c.execute(sql, (channel, channel))
			return 1

		def close(self):
			self.db.close()
		
		def peerstatus (self, technology, peer, status):
			sql = """INSERT INTO peers (technology, peer, status) VALUES (%s,%s,%s) ON DUPLICATE KEY UPDATE status=%s"""
			try:
				self.c.execute(sql, (technology, peer, status, status))
			except MySQLdb.OperationalError, reason:
				logging.critical("MySQLdb: %s" % reason)
				if not self._reconnect():
					return 0
				else:
					self.c.execute(sql, (technology, peer, status, status))
			return 1

		def agentstatus (self, agent, channel, status):
			sql = """INSERT INTO agents (agent, channel, status, laststate) VALUES (%s,%s,%s,NULL) ON DUPLICATE KEY UPDATE status=%s,laststate=NULL"""
			try:
				self.c.execute(sql, (agent, channel, status, status))
			except MySQLdb.OperationalError, reason:
				logging.critical("MySQLdb: %s" % reason)
				if not self._reconnect():
					return 0
				else:
					self.c.execute(sql, (agent, channel, status, status))
			return 1

		def _reconnect(self):
			self.close()
			nretry = self.dbretries
			while nretry > 0 or nretry <= -1:
				try:
					self.db = MySQLdb.connect(host=self.dbhost, user=self.dbuser, passwd=self.dbpass, db=self.dbname)
					self.c = self.db.cursor()
					return 1
				except MySQLdb.OperationalError, reason:
					logging.critical("MySQLdb: %s" % reason)
					nretry = nretry - 1
					# wait 3 seconds before trying to connect again.
					time.sleep(3)
			return 0

class TestPersistData (unittest.TestCase):
	
	def setUp(self):
		self.pd = PersistData("localhost", "root", "passw0rd", "asterisk")
	
	def testSingleton(self):
		tmp = PersistData()
		self.assertEqual(self.pd.dbhost, "localhost")
		self.assertEqual(self.pd.dbuser, "root")
		self.assertEqual(self.pd.dbpass, "passw0rd")
		self.assertEqual(self.pd.dbhost, tmp.dbhost)
		self.assertEqual(self.pd.dbpass, tmp.dbpass)
		self.assertEqual(self.pd.dbuser, tmp.dbuser)

if __name__ == "__main__":
	suite = unittest.TestLoader().loadTestsFromTestCase(TestPersistData)
	res = unittest.TextTestRunner(verbosity=2).run(suite)
